// -*- c++ -*-
#ifndef __CVECTOR2D_H__
#define __CVECTOR2D_H__

#include "StdDefs.h"
#include "CMathFixed.h"
 


// CVector2d* must maintain casting ability with (fixed*).
// CVector2d may not have virtuals, inherited, or instantiated data.


class CVector2d
{
public:
	inline explicit CVector2d( no_ctor_modify n ) { }
	CVector2d(){}
	CVector2d( fixed degrees );
	CVector2d( const fixed* ij );
	CVector2d( fixed i, fixed j ); 
	CVector2d( const CVector2d& v ); 
	~CVector2d(){}

	fixed				Length() const;

	void				Clear();
	void				Set( fixed degrees );
	void				Set( fixed i, fixed j );
	void				Set( const CVector2d& v );

	CVector2d&			Normalize();
	CVector2d&			ProjOnto( const CVector2d& v );
	CVector2d&			LerpTo( const CVector2d& v, fixed u ); 
	CVector2d&			Rotate( fixed degrees );

	fixed				Angle() const;
	fixed				Angle( CVector2d& v ) const;
	fixed				AngleTo( CVector2d& v ) const;

	fixed				ShortestDistanceToLineSegment( class CLineSegment2d& segment, 
													   CVector2d& pntOfIntersection ) const;
	fixed				ShortestDistanceToLineSegment( const CVector2d& segV0, const CVector2d& segV1,
													   CVector2d& pntOfIntersection ) const;

	fixed				IsOnLineSegment( class CLineSegment2d& segment ) const;
	fixed				IsOnLineSegment( const CVector2d& segV0, const CVector2d& segV1 ) const;

	fixed				IsInPoly( const CVector2d* vertex, int vertexCount ) const;

	CVector2d&			operator=( fixed degrees );
	CVector2d&			operator=( const fixed* ij );

	CVector2d&			operator+=( const CVector2d& v );
	CVector2d&			operator+=( fixed val );
	CVector2d&			operator-=( const CVector2d& v );
	CVector2d&			operator-=( fixed val );
	CVector2d&			operator*=( fixed val );
	CVector2d&			operator*=( const class CMatrix2d& a );
	CVector2d&			operator/=( fixed val );

	fixed&				operator[]( uint32 idx );
	fixed				operator[]( uint32 idx ) const;

	friend CVector2d	operator+( const CVector2d& v1, const CVector2d& v2 );
	friend CVector2d	operator+( const CVector2d& v, fixed val );
	friend CVector2d	operator+( fixed val, const CVector2d& v );
	friend CVector2d	operator-( const CVector2d& v1, const CVector2d& v2 );
	friend CVector2d	operator-( const CVector2d& v, fixed val );
	friend CVector2d	operator-( fixed val, const CVector2d& v );
	friend fixed		operator*( const CVector2d& v1, const CVector2d& v2 );
	friend CVector2d	operator*( const CVector2d& v, fixed val );
	friend CVector2d	operator*( fixed val, const CVector2d& v );
	friend CVector2d	operator*( const class CMatrix2d& a, const CVector2d& x );
	friend CVector2d	operator/( const CVector2d& v, fixed val );
	friend CVector2d	operator/( fixed val, const CVector2d& v );
	
	fixed				m_i; 
	fixed				m_j;
};


 

inline 
CVector2d::CVector2d( fixed degrees )
{ 
	m_i = CMathFixed::Cos( degrees );
	m_j = CMathFixed::Sin( degrees );
}


inline 
CVector2d::CVector2d( const fixed* ij )
{ 
	ASSERT( ij );

	m_i = *ij;
	m_j = *( ij + 1 );
}


inline 
CVector2d::CVector2d( fixed i, fixed j )
{ 
	m_i = i; 
	m_j = j; 
}


inline 
CVector2d::CVector2d( const CVector2d& v )
{
	m_i = v.m_i; 
	m_j = v.m_j; 
}


inline
fixed CVector2d::Length() const
{
	return CMathFixed::Sqrt( ( *this * *this ) );
}


inline
void CVector2d::Clear()
{
	m_i = 0; 
	m_j = 0;
}

inline void
CVector2d::Set( fixed degrees )
{ 
	m_i = CMathFixed::Cos( degrees );
	m_j = CMathFixed::Sin( degrees );
}

inline
void CVector2d::Set( fixed i, fixed j )
{
	m_i = i; 
	m_j = j;
}


inline 
void CVector2d::Set( const CVector2d& v )
{
	m_i = v.m_i; 
	m_j = v.m_j; 
}



inline
CVector2d& CVector2d::Normalize()
{
	fixed len = Length();

	if( len )
		*this /= len;

	return *this;
}


inline
CVector2d& CVector2d::operator=( fixed degrees )
{
	m_i = CMathFixed::Cos( degrees );
	m_j = CMathFixed::Sin( degrees );

	return *this;
}


inline
CVector2d& CVector2d::operator=( const fixed* ij )
{
	ASSERT( ij );

	m_i = *ij;
	m_j = *( ij + 1 );

	return *this;
}
	

inline
CVector2d& CVector2d::operator+=( const CVector2d& v )
{
	m_i += v.m_i;
	m_j += v.m_j;

	return *this;
}


inline
CVector2d& CVector2d::operator+=( fixed val )
{
	m_i += val;
	m_j += val;

	return *this;
}


inline
CVector2d& CVector2d::operator-=( const CVector2d& v )
{
	m_i -= v.m_i;
	m_j -= v.m_j;

	return *this;
}


inline
CVector2d& CVector2d::operator-=( fixed val )
{
	m_i -= val;
	m_j -= val;

	return *this;
}


inline
CVector2d& CVector2d::operator*=( fixed val )
{
	m_i = CMathFixed::Mul( m_i, val );
	m_j = CMathFixed::Mul( m_j, val );

	return *this;
}


inline
CVector2d& CVector2d::operator/=( fixed val )
{
	m_i = CMathFixed::Div( m_i, val );
	m_j = CMathFixed::Div( m_j, val );

	return *this;
}


inline
fixed& CVector2d::operator[]( uint32 idx )
{
	ASSERT( idx < 2 );

	return *( ( (fixed*)this ) + idx );
}


inline
fixed CVector2d::operator[]( uint32 idx ) const
{
	ASSERT( idx < 2 );

	return *( ( (fixed*)this ) + idx );
}


inline 
CVector2d operator+( const CVector2d& v1, const CVector2d& v2 )
{ 
	return CVector2d( v1.m_i + v2.m_i, v1.m_j + v2.m_j ); 
}


inline 
CVector2d operator+( const CVector2d& v, fixed val )
{ 
	return CVector2d( v.m_i + val, v.m_j + val ); 
}


inline 
CVector2d operator+( fixed val, const CVector2d& v )
{ 
	return CVector2d( val + v.m_i, val + v.m_j ); 
}


inline 
CVector2d operator-( const CVector2d& v1, const CVector2d& v2 )
{ 
	return CVector2d( v1.m_i - v2.m_i,  v1.m_j - v2.m_j ); 
}


inline 
CVector2d operator-( const CVector2d& v, fixed val )
{ 
	return CVector2d( v.m_i - val, v.m_j - val ); 
}


inline 
CVector2d operator-( fixed val, const CVector2d& v )
{ 
	return CVector2d( val - v.m_i, val - v.m_j ); 
}


inline
fixed operator*( const CVector2d& v1, const CVector2d& v2 )
{
	return CMathFixed::Mul( v1.m_i, v2.m_i ) + CMathFixed::Mul( v1.m_j, v2.m_j );
}


inline
CVector2d operator*( const CVector2d& v, fixed val )
{
	return CVector2d( CMathFixed::Mul( v.m_i, val ), CMathFixed::Mul( v.m_j, val ) );
}


inline
CVector2d operator*( fixed val, const CVector2d& v )
{
	return CVector2d( CMathFixed::Mul( val, v.m_i ), CMathFixed::Mul( val, v.m_j ) );
}


inline
CVector2d operator/( const CVector2d& v, fixed val )
{
	return CVector2d( CMathFixed::Div( v.m_i, val ), CMathFixed::Div( v.m_j, val ) );
}


inline
CVector2d operator/( fixed val, const CVector2d& v )
{
	return CVector2d( CMathFixed::Div( val, v.m_i ), CMathFixed::Div( val, v.m_j ) );
}

inline
boolean operator==( const CVector2d& v1, const CVector2d& v2 )
{
    return v1.m_i == v2.m_i && v1.m_j == v2.m_j;
}

inline
boolean operator!=( const CVector2d& v1, const CVector2d& v2 )
{
    return !(v1 == v2);
}



 

#endif // __CVECTOR2D_H__
